#include "LobbyClient.h"

#include "LobbyPersistentData.h"
#include "LobbyPlayer.h"
#include "LobbyTypes.h"

#include "WONRouting/RoutingTypes.h"

using namespace WONAPI;

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static const LobbyClientMap& GetEmptyClientMap()
{
	static LobbyClientMap aMap;
	return aMap;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyClient::LobbyClient()
{
	mClientId = RoutingId_Invalid;
	
	mClientFlags = 0;
	mWONUserId = 0;
	mCDKeyId = 0;

	mChatFlags = 0;
	mGameFlags = 0;

	mChatGroupId = RoutingId_Invalid;
	mGameGroupId = RoutingId_Invalid;

	mIgnored = false;
	mBlocked = false;
	mIsFriend = false;
	mIsGameCaptain = false;
	mIsChatCaptain = false;
	mIsInvited = false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyClient::~LobbyClient()
{

}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClient::ClearGroupInfo(unsigned short theId, bool isGame)
{
	if(isGame)
	{
		if(theId==mGameGroupId)
		{
			mGameGroupId = RoutingId_Invalid;
			mGameFlags = 0;
			mIsGameCaptain = false;
		}
	}
	else
	{
		if(theId==mChatGroupId)
		{
			mChatGroupId = RoutingId_Invalid;
			mChatFlags = 0;
			mIsChatCaptain = false;
		}
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::InChat()
{
	return mChatGroupId!=RoutingId_Invalid;	
}
	
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::InGame()
{
	return mGameGroupId!=RoutingId_Invalid;	
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClient::Init(const RoutingClientInfo *theClient)
{
	mName = theClient->mName;
	mClientFlags = theClient->mFlags;
	mClientId = theClient->mId;
	mWONUserId = theClient->mWONUserId;
	mCDKeyId = theClient->mCDKeyId;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClient::CheckPersistentData()
{
	mIgnored = LobbyPersistentData::IsIgnored(mName);
	mBlocked = LobbyPersistentData::IsBlocked(mCDKeyId);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::IsFriend()
{
	return mIsFriend;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::IsAnonymous()
{
	return mClientFlags&RoutingClientFlag_IsAnonymous?true:false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::IsMuted(bool checkGame)
{
	if(mClientFlags & RoutingClientFlag_IsMuted)
		return true;

	if(checkGame)
		return mGameFlags&RoutingMemberFlag_IsMuted?true:false;
	else
		return mChatFlags&RoutingMemberFlag_IsMuted?true:false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::IsAway()
{
	return mClientFlags&RoutingClientFlag_IsAway?true:false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::IsAdmin()
{
	return mClientFlags&RoutingClientFlag_IsAdmin?true:false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::IsModerator()
{
	return mClientFlags&RoutingClientFlag_IsModerator?true:false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::IsCaptain(bool checkGame)
{
	if(checkGame)
		return mIsGameCaptain;
	else
		return mIsChatCaptain;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClient::SetIsCaptain(bool isCaptain, bool isGame)
{
	if(isGame)
		mIsGameCaptain = isCaptain;
	else
		mIsChatCaptain = isCaptain;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClient::SetPlayer(LobbyPlayer *thePlayer)
{
	mPlayer = thePlayer;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::IsPlayer()
{
	return mPlayer.get()!=NULL;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::IsPlayerReady()
{
	if(mPlayer.get()!=NULL)
		return mPlayer->IsReady();
	else
		return false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
unsigned short LobbyClient::GetPlayerPing()
{
	if(mPlayer.get()!=NULL)
		return mPlayer->GetPing();
	else
		return LobbyPing_None;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClient::SameTeam(LobbyClient *theClient)
{
	if(theClient==NULL)
		return false;
	else if(mPlayer==NULL || theClient->mPlayer==NULL)
		return false;
	else
		return mPlayer->SameTeam(theClient->mPlayer);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyClientList::LobbyClientList()
{
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyClientList::~LobbyClientList()
{
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClientList::Clear()
{
	mClientMap.clear();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClientList::UpdateClients(const RoutingClientMap &theMap)
{
	LobbyClientMap::iterator anItr1 = mClientMap.begin();
	LobbyClientMap::iterator anInsertPoint = mClientMap.begin();
	RoutingClientMap::const_iterator anItr2 = theMap.begin();
	while(anItr1!=mClientMap.end() && anItr2!=theMap.end())
	{
		if(anItr1->first<anItr2->first)
			mClientMap.erase(anItr1++);
		else if(anItr2->first < anItr1->first)
		{	
			LobbyClientPtr aClient = new LobbyClient;
			aClient->Init(anItr2->second);
			anInsertPoint = mClientMap.insert(anInsertPoint, LobbyClientMap::value_type(aClient->GetClientId(),aClient));
			++anItr2;
		}
		else 
		{
			LobbyClientPtr aClient = anItr1->second;
			aClient->Init(anItr2->second);
			++anItr1; ++anItr2;
		}
	}

	if(anItr1!=mClientMap.end())
		mClientMap.erase(anItr1, mClientMap.end());

	while(anItr2!=theMap.end())
	{
		LobbyClientPtr aClient = new LobbyClient;
		aClient->Init(anItr2->second);
		anInsertPoint = mClientMap.insert(anInsertPoint, LobbyClientMap::value_type(aClient->GetClientId(),aClient));
		++anItr2;
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClientList::CheckPersistentData()
{
	for(LobbyClientMap::iterator anItr=mClientMap.begin(); anItr!=mClientMap.end(); ++anItr)
	{
		LobbyClient *aClient = anItr->second;
		aClient->CheckPersistentData();
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClientList::AddClient(LobbyClient *theClient)
{
	mClientMap[theClient->GetClientId()] = theClient;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyClient* LobbyClientList::GetClient(unsigned short theId)
{
	LobbyClientMap::iterator anItr = mClientMap.find(theId);
	if(anItr!=mClientMap.end())
		return anItr->second;
	else
		return NULL;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyClientPtr LobbyClientList::RemoveClient(unsigned short theId)
{
	LobbyClientMap::iterator anItr = mClientMap.find(theId);
	if(anItr!=mClientMap.end())
	{
		LobbyClientPtr aClient = anItr->second;
		mClientMap.erase(anItr);
		return aClient;
	}
	else
		return NULL;	
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyClient* LobbyClientList::GetClientByWONId(unsigned long theWONId)
{
	for(LobbyClientMap::iterator anItr=mClientMap.begin(); anItr!=mClientMap.end(); ++anItr)
	{
		LobbyClient *aClient = anItr->second;
		if(aClient->GetWONUserId()==theWONId)
			return aClient;
	}

	return NULL;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClientList::ClearInvites()
{
	for(LobbyClientMap::iterator anItr=mClientMap.begin(); anItr!=mClientMap.end(); ++anItr)
	{
		LobbyClient *aClient = anItr->second;
		aClient->SetIsInvited(false);
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyClientListItr::LobbyClientListItr(LobbyClientList *theList) : mMap(theList?theList->GetClientMap():GetEmptyClientMap())
{
	Rewind();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyClientListItr::HasMoreClients()
{
	return mItr!=mMap.end();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyClient* LobbyClientListItr::GetNextClient()
{
	if(mItr!=mMap.end())
	{
		LobbyClient *aClient = mItr->second;
		++mItr;

		return aClient;
	}
	else
		return NULL;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyClientListItr::Rewind()
{
	mItr = mMap.begin();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyPlayerList::LobbyPlayerList(LobbyClientList *theList) : mMap(theList?theList->GetClientMap():GetEmptyClientMap())
{
	Rewind();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool LobbyPlayerList::HasMorePlayers()
{
	if(mFoundNextPlayer)
		return true;

	while(mItr!=mMap.end())
	{
		LobbyClient *aClient = mItr->second;
		if(aClient->GetPlayer()!=NULL)
		{
			mFoundNextPlayer = true;
			return true;	
		}

		++mItr;
	}

	return false;
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
LobbyPlayer* LobbyPlayerList::GetNextPlayer(LobbyClient **theClient)
{
	if(HasMorePlayers())
	{
		LobbyClient *aClient = mItr->second;
		if(theClient!=NULL)
			*theClient = aClient;

		LobbyPlayer *aPlayer = aClient->GetPlayer();
		mFoundNextPlayer = false;
		++mItr;
		return aPlayer;
	}
	else
		return NULL;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void LobbyPlayerList::Rewind()
{
	mItr = mMap.begin();
	mFoundNextPlayer = false;
}
